package com.guapi.controller;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTValidator;
import com.guapi.Application;
import com.guapi.annotation.SelfController;
import com.guapi.dao.*;
import com.guapi.event.EventProducer;
import com.guapi.exception.SelfException;
import com.guapi.service.AuthService;
import com.guapi.service.MenuService;
import com.guapi.service.UserService;
import com.guapi.util.RedisUtil;
import com.guapi.util.request.SelfRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;

@RequestMapping("/common")
@ResponseBody
@SelfController
public class CommonController extends BaseController {
    @Autowired
    private UserService userService;
    @Autowired
    private MenuService menuService;
    @Autowired
    private AuthService authService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private EventProducer eventProducer;
    @Autowired
    private HttpServletRequest request;


    /**
     * 验证注册操作
     * @param request
     * @param user
     * @param validCode
     * @return
     */
    @RequestMapping("/register/{validCode}")
    public ResponseData doRegister(HttpServletRequest request, @RequestBody User user, @PathVariable("validCode") String validCode) {
        SelfRequest selfRequest = createRequest(request);
        responseData = new ResponseData();
        String emailKey = RedisUtil.getEmailKey(user.getEmail());
        if (StrUtil.equals((String) redisTemplate.opsForValue().get(emailKey), validCode)) {
            user.setHeaderUrl(defaultHeader);
            User dbuser = userService.saveUser(user, false);
            if (ObjectUtil.equal(dbuser, user)) {
                responseData.setData("user", user);
                responseData.setSuccess(true);
                redisTemplate.expire(emailKey, 0, TimeUnit.SECONDS);
                Event event = new Event();
                event.setTopic(TOPIC_USER_REGISTER)
                        .setEntityType(SYSTEM_MESSAGE)
                        .setUserId(dbuser.getId())
                        .setData(DATA_KEY_CONTENT,String.format(REGISTER_CONTENT,user.getUsername()));
                eventProducer.sendEvent(event);
            } else {
                throw new SelfException("401", "当前用户已存在，请检查您的邮箱信息或选择忘记密码");
            }
        } else {
            responseData.setSuccess(false);
            responseData.setCode("403");
            responseData.setMessage("验证码不正确！！");
        }


        return this.responseData;
    }

    /**
     * 登录
     * @param request
     * @param user
     * @return
     */
    @RequestMapping("/login")
    public ResponseData doLogin(HttpServletRequest request, @RequestBody User user) {
        SelfRequest selfRequest = createRequest(request);
        User loginUser = userService.doLogin(user);
        loginUser.setPassword("");
        Date nowDate = new Date();
        String token = JWT.create()
                .setPayload("user", loginUser)
                .setIssuedAt(nowDate)
                .setExpiresAt(new Date(nowDate.getTime() + TOKEN_EXPIRE_DATE))
                .setKey(TOKEN_SIGNATURE).sign();
        if (Objects.equals(loginUser.getHeaderUrl(), NULL)) {
            loginUser.setHeaderUrl(null);
        } else {
            File headerFile = new File(resourcePath + "\\" + loginUser.getHeaderUrl());
            if (headerFile.exists()) {
                String userHeaderKey = RedisUtil.getUserHeaderKey(String.valueOf(loginUser.getId()));
                byte[] headerBytes = FileUtil.readBytes(headerFile);
                redisTemplate.opsForValue().set(userHeaderKey, Base64.encode(headerBytes));
            }
        }
        responseData.setData("token", token);
        responseData.setData("user", loginUser);
        responseData.setSuccess(true);
        return responseData;
    }

    /**
     * 发送找回密码邮件
     * @param request
     * @param user
     * @return
     */
    @RequestMapping("/forget")
    public ResponseData doForget(HttpServletRequest request, @RequestBody User user) {
        SelfRequest selfRequest = createRequest(request);
        String origin = request.getHeader("Origin") + "/";
        if (userService.getOne(user) == null) {
            throw new SelfException("不存在此用户！");
        }
        String sign = JWT.create().setKey(TOKEN_SIGNATURE)
                .setExpiresAt(DateUtil.offset(DateUtil.date(), DateField.SECOND, 60 * 3))
                .sign();
        MailUtil.send(user.getEmail(),
                "找回密码服务",
                setForgetMail(user.getEmail(), origin + "reset/" + sign + "/" + user.getEmail()),
                true);
        responseData.setSuccess(true);
        return responseData;
    }

    /**
     * 重置密码
     * @param request
     * @param map
     * @return
     */
    @RequestMapping("/reset")
    public ResponseData resetPassword(HttpServletRequest request, @RequestBody Map map) {
        SelfRequest selfRequest = createRequest(request);
        System.out.println(map);
        try {
            JWTValidator.of(String.valueOf(map.get("token"))).validateDate();

            User user = new User();
            user.setEmail((String) map.get("email"));
            user.setAccount((String) map.get("password"));
            user.setPassword((String) map.get("account"));

            userService.doForget(user);
            //修改密码
        } catch (ValidateException e) {
            throw new SelfException("链接已过期！");
        }
        return responseData;
    }

    /**
     * 登出
     * @param request
     * @param user
     * @return
     */
    @RequestMapping("/logout")
    public ResponseData doLogout(HttpServletRequest request, @RequestBody User user) {
        SelfRequest selfRequest = createRequest(request);
        //清除token信息
        SecurityContextHolder.clearContext();
        return responseData;
    }

    /**
     * 获取权限相关的路由列表
     * @param request
     * @return
     */
    @RequestMapping("/routeList")
    public ResponseData getRouteList(HttpServletRequest request) {
        SelfRequest selfRequest = createRequest(request);
        List<Menu> routeList = menuService.list();
        //需要通过角色权限配置
        User loginUser = getLoginUser();
        if (loginUser != null) {
            List<Auth> auths = authService.getByConditions(new Auth().setRoleId(Integer.valueOf(loginUser.getRole())));
            if (CollectionUtil.isEmpty(auths)) {
                SecurityContextHolder.clearContext();
                throw new SelfException("403.1", "该用户没有分配角色或角色没有权限，请联系管理员处理");
            }
            ArrayList<Integer> menuId = new ArrayList<>();
            auths.forEach(auth -> menuId.add(auth.getMenuId()));
            routeList = menuService.listByIds(menuId);
        }
        responseData.setRows(routeList);
        responseData.setSuccess(true);
        return responseData;
    }

    /**
     * 登录验证码
     * @param request
     * @return
     * @throws Exception
     */
    @RequestMapping("/random")
    public ResponseData getRandomCode(HttpServletRequest request) throws Exception {

        responseData = new ResponseData();
        SelfRequest selfRequest = createRequest(request);
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < 3; i++) {
            char[] symbols = {'+', '-', '*'};
            int index = RandomUtil.randomInt(3);
            int randomInt = RandomUtil.randomInt(20);
            code.append(randomInt).append(symbols[index]);
        }
        code = new StringBuilder(code.substring(0, code.length() - 1));
        String result = String.valueOf((int) NumberUtil.calculate(code.toString()));
        code.append("=?");
        responseData.setData("result", result);
        responseData.setData("code", code);
        responseData.setSuccess(true);
        return responseData;
    }

    /**
     * 发送注册邮件
     * @param request
     * @param data
     * @return
     */
    @RequestMapping("/mailCode")
    public ResponseData sendMailCode(HttpServletRequest request, @RequestBody Map data) {
        responseData = new ResponseData();

        String activeCode = RandomUtil.randomString(RandomUtil.randomInt(6, 9));
        String email = data.get("email").toString();
        String emailKey = RedisUtil.getEmailKey(email);
        User user = new User();
        user.setEmail(email);
        List<User> userList = userService.getByConditions(user);
        if (CollectionUtil.isEmpty(userList)) {
            redisTemplate.opsForValue().set(emailKey, activeCode);
            redisTemplate.expire(emailKey, 180, TimeUnit.SECONDS);
            try {
                MailUtil.send(email, "在线接发单系统注册", setMailArgs(email, activeCode), true);
            } catch (Exception e) {
                throw new SelfException("注册邮件发送失败", e);
            }
        } else {
            throw new SelfException("403", "此邮箱已被注册，请登录！");
        }
        responseData.setSuccess(true);
        return responseData;
    }

    /**
     * 注册网站头像
     * @param request
     * @param response
     * @param data
     */
    @RequestMapping("/header")
    public void getUserHeader(HttpServletRequest request, HttpServletResponse response, @RequestBody Map data) {
        User loginUser = getLoginUser();
        String userHeaderKey = RedisUtil.getUserHeaderKey(String.valueOf(loginUser.getId()));
        byte[] userHeader = Base64.decode((String) redisTemplate.opsForValue().get(userHeaderKey));
        OutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            outputStream.write(userHeader);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * /guapi/common/test,用于测试
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping("/test")
    public ResponseData testAction(HttpServletRequest request) throws IOException {
        responseData = new ResponseData();


        //URL resource = Application.class.getClassLoader().getResource("static/resetPassword.html");
        //System.out.println("路径是：" + resource.getPath());
        //String file = resource.getFile();
        //System.out.println(file);
        //FileReader fileReader = new FileReader(file);
        //System.out.println(fileReader.readString());

        ClassLoader classLoader = Application.class.getClassLoader();
        URL resource = classLoader.getResource("static/resetPassword.html");
        System.out.println("路径是：" + resource.getPath());
        BufferedReader reader = new BufferedReader(new InputStreamReader(resource.openStream(), StandardCharsets.UTF_8));
        String line;
        String result = "";
        while ((line = reader.readLine()) != null) {
            result += line;
        }
        System.out.println("内容是：" + result);
        responseData.setData("GUAPI_TEST", "TEST_SUCCESS");
        responseData.setSuccess(true);
        return responseData;
    }

    @RequestMapping("/kafka")
    public ResponseData testKafka(HttpServletRequest request){
        responseData=new ResponseData();

        eventProducer.sendEvent(new Event().setTopic("TEST").setData("TEST","KAFKA_TEST"));
        responseData.setSuccess(true);
        responseData.setData("TEST","KAFKA_TEST");
        return responseData;
    }
}
